package com.sky.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sky.context.BaseContext;
import com.sky.dto.OrdersPageQueryDTO;
import com.sky.dto.OrdersPaymentDTO;
import com.sky.dto.OrdersSubmitDTO;
import com.sky.entity.*;
import com.sky.exception.OrderBusinessException;
import com.sky.mapper.*;
import com.sky.result.PageResult;
import com.sky.service.OrderDetailService;
import com.sky.service.OrderService;
import com.sky.utils.WeChatPayUtil;
import com.sky.vo.OrderPaymentVO;
import com.sky.vo.OrderSubmitVO;
import com.sky.vo.OrderVO;
import com.sky.vo.TurnoverReportVO;
import com.sky.webSocket.WebSocketServer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 订单逻辑层实现类
 *
 * @Author mr.lcc
 * @Data 2025/5/26 20:50
 */
@Service
@Slf4j
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Orders> implements OrderService {

    @Autowired
    private OrderDetailService orderDetailService;
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private OrderDetailMapper orderDetailMapper;
    @Autowired
    private AddressBookMapper addressBookMapper;
    @Autowired
    private ShoppingCartMapper shoppingCartMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private WeChatPayUtil weChatPayUtil;
    @Autowired
    private WebSocketServer webSocketServer;

    /**
     * 用户下单
     *
     * @param ordersSubmitDTO
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public OrderSubmitVO submitOrder(OrdersSubmitDTO ordersSubmitDTO) {
        // 1.健壮性校验 || 异常情况的处理
        if (ObjectUtil.isEmpty(ordersSubmitDTO)) {
            throw new RuntimeException("订单参数为空！");
        }
        AddressBook address = addressBookMapper.getById(ordersSubmitDTO.getAddressBookId());
        if (ObjectUtil.isEmpty(address)) {
            throw new RuntimeException("收货地址为空！");
        }

        // 2.查询当前用户的购物车数据
        Long userId = BaseContext.getCurrentId();
        if (ObjectUtil.isEmpty(userId)) {
            throw new RuntimeException("用户为空！");
        }
        LambdaQueryWrapper<ShoppingCart> shoppingQueryWrapper = new LambdaQueryWrapper<>();
        shoppingQueryWrapper.eq(ShoppingCart::getUserId, userId);
        List<ShoppingCart> shoppingCartList = shoppingCartMapper.selectList(shoppingQueryWrapper);
        if (ObjectUtil.isEmpty(shoppingCartList)) {
            throw new RuntimeException("购物车为空！");
        }

        // 3.向订单表插入1条数据
        Orders orders = new Orders();
        BeanUtils.copyProperties(ordersSubmitDTO, orders);
        // 设置手机号
        orders.setPhone(address.getPhone());
        // 设置收货地址
        orders.setAddress(address.getDetail());
        // 收货人
        orders.setConsignee(address.getConsignee());
        // 订单号
        String numberData = IdUtil.fastSimpleUUID();
        orders.setNumber(numberData);
        // 设置用户id
        orders.setUserId(userId);
        // 订单状态 1=代付款
        orders.setStatus(Orders.PAID);
        // 支付方式 0=微信支付
        orders.setPayMethod(Orders.UN_PAID);
        // 创建时间
        orders.setOrderTime(LocalDateTime.now());

        boolean save = this.save(orders);
        if (!save) {
            throw new RuntimeException("保存订单失败,请重新尝试！");
        }

        // 4.订单明细数据
        List<OrderDetail> orderDetailList = new ArrayList<>();
        for (ShoppingCart cart : shoppingCartList) {
            OrderDetail orderDetail = new OrderDetail();
            BeanUtils.copyProperties(cart, orderDetail);
            orderDetail.setOrderId(orders.getId());
            orderDetailList.add(orderDetail);
        }

        // 5.向明细表插入n条数据
        boolean orderDetailSave = orderDetailService.saveBatch(orderDetailList);
        if (!orderDetailSave) {
            throw new RuntimeException("保存订单明细失败,请重新尝试！");
        }

        // 6.清理购物车中的数据
        boolean remove = shoppingCartMapper.delete(shoppingQueryWrapper) > 0;
        if (!remove) {
            throw new RuntimeException("删除购物车失败！");
        }

        // 7.封装返回结果
        OrderSubmitVO orderSubmitVO = OrderSubmitVO.builder()
                // 订单id
                .id(orders.getId())
                // 订单号
                .orderNumber(orders.getNumber())
                // 订单金额
                .orderAmount(orders.getAmount())
                // 下单时间
                .orderTime(orders.getOrderTime()).build();
        return orderSubmitVO;
    }

    /**
     * 订单支付
     *
     * @param ordersPaymentDTO
     * @return
     */
    public OrderPaymentVO payment(OrdersPaymentDTO ordersPaymentDTO) {
        // 当前登录用户id
        Long userId = BaseContext.getCurrentId();
        User user = userMapper.selectById(userId);

//        //调用微信支付接口，生成预支付交易单
//        JSONObject jsonObject = weChatPayUtil.pay(
//                ordersPaymentDTO.getOrderNumber(), //商户订单号
//                new BigDecimal(0.01), //支付金额，单位 元
//                "苍穹外卖订单", //商品描述
//                user.getOpenid() //微信用户的openid
//        );
//
//        if (jsonObject.getString("code") != null && jsonObject.getString("code").equals("ORDERPAID")) {
//            throw new OrderBusinessException("该订单已支付");
//        }

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("code", "ORDERPAID");

        OrderPaymentVO vo = jsonObject.toJavaObject(OrderPaymentVO.class);
        vo.setPackageStr(jsonObject.getString("package"));

        // 替代微信支付成功后的数据库订单状态更新，直接在这里更新了
        // 根据订单号查询当前用户的该订单
        LambdaQueryWrapper<Orders> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Orders::getNumber, ordersPaymentDTO.getOrderNumber());
        Orders ordersDB = orderMapper.selectOne(queryWrapper);

        // 根据订单id更新订单的状态、支付方式、支付状态、结账时间
        Orders orders = new Orders();
        orders.setId(ordersDB.getId());
        orders.setStatus(Orders.TO_BE_CONFIRMED);
        orders.setPayStatus(Orders.PAID);
        orders.setCheckoutTime(LocalDateTime.now());
//        Orders orders = Orders.builder()
//                .id(ordersDB.getId())
//                .status(Orders.TO_BE_CONFIRMED) // 订单状态，待接单
//                .payStatus(Orders.PAID) // 支付状态，已支付
//                .checkoutTime(LocalDateTime.now()) // 更新支付时间
//                .build();

        orderMapper.updateById(orders);

        //通过websocket向客户端浏览器推送消息 type orderId content
        Map map = new HashMap();
        map.put("type", 1); //1表示来单提醒，2表示客户催单
        map.put("orderId", ordersDB.getId());//获得订单Id
        //map.put("content", orders.getNumber());
        String json = JSON.toJSONString(map); //把map转成JSON字符串
        webSocketServer.sendToAllClient(json); //向页面推送消息

        return vo;
    }

    /**
     * 支付成功，修改订单状态
     *
     * @param outTradeNo
     */
    public void paySuccess(String outTradeNo) {

        // 根据订单号查询订单
        LambdaQueryWrapper<Orders> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Orders::getNumber, outTradeNo);
        Orders ordersDB = orderMapper.selectOne(queryWrapper);

        // 根据订单id更新订单的状态、支付方式、支付状态、结账时间
        Orders orders = Orders.builder().id(ordersDB.getId()).status(Orders.TO_BE_CONFIRMED).payStatus(Orders.PAID).checkoutTime(LocalDateTime.now()).build();

        orderMapper.updateById(orders);

        //通过websocket向客户端浏览器推送消息 type orderId content
        Map map = new HashMap();
        map.put("type", 1); //1表示来单提醒，2表示客户催单
        map.put("orderId", ordersDB.getId());//获得订单Id
        map.put("content", "订单号：" + orders.getNumber());

        String json = JSON.toJSONString(map); //把map转成JSON字符串
        webSocketServer.sendToAllClient(json); //向页面推送消息
    }

    /**
     * 历史订单查询
     *
     * @param dto
     * @return
     */
    @Override
    public PageResult pageList(OrdersPageQueryDTO dto) {
        // 1. 参数校验
        if (ObjectUtil.isEmpty(dto)) {
            throw new OrderBusinessException("查询历史订单错误！");
        }

        // 2. 构建订单主表查询条件
        Long userId = BaseContext.getCurrentId();
        Page<Orders> page = new Page<>(dto.getPage(), dto.getPageSize());
        this.lambdaQuery().eq(Orders::getUserId, userId).eq(ObjectUtil.isNotEmpty(dto.getStatus()), Orders::getStatus, dto.getStatus()).orderByDesc(Orders::getOrderTime).page(page);

        List<OrderVO> list = new ArrayList<>();
        if (page.getTotal() > 0) {
            List<Orders> records = page.getRecords();

            // 3. 订单状态处理
            List<Orders> newOrders = OrderStatusHandle(records);

            if (CollUtil.isNotEmpty(newOrders)) {
                // 收集所有订单ID
                List<Long> orderIdList = newOrders.stream().map(Orders::getId).collect(Collectors.toList());

                // 4. 批量查询所有订单详情
                List<OrderDetail> allDetails = orderDetailService.list(new LambdaQueryWrapper<OrderDetail>().in(OrderDetail::getOrderId, orderIdList));

                // 5. 按照 orderId 分组，便于后续查找
                Map<Long, List<OrderDetail>> detailMap = allDetails.stream().collect(Collectors.groupingBy(OrderDetail::getOrderId));

                // 6. 封装 VO 数据
                for (Orders order : newOrders) {
                    OrderVO orderVO = new OrderVO();
                    BeanUtils.copyProperties(order, orderVO);
                    orderVO.setOrderDetailList(detailMap.getOrDefault(order.getId(), Collections.emptyList()));
                    list.add(orderVO);
                }
            }
        }
        return new PageResult(page.getTotal(), list);
    }

    /**
     * 处理订单状态
     *
     * @param records
     * @return
     */
    private List<Orders> OrderStatusHandle(List<Orders> records) {
        // 1. 等待支付时间为15分钟内，超时订单自动变成已取消状态；
        LocalDateTime sysNow = LocalDateTime.now();
        records.forEach(o -> {
            LocalDateTime orderTime = o.getOrderTime();
            // 判断订单时间是否早于 ’ 当前时间 - 15分钟
            if (orderTime != null && orderTime.isBefore(sysNow.minusMinutes(15))) {
                // 超过15分钟，更新订单状态为已取消
                o.setStatus(Orders.CANCELLED);
            }
        });
        return records;
    }

    /**
     * 查询订单详情
     *
     * @param id
     * @return
     */
    @Override
    public OrderVO details(Integer id) {
        // 健壮性判断
        if (id == null || id <= 0) {
            throw new OrderBusinessException("查询订单详情参数为空！");
        }

        // 查询订单
        Orders order = this.getById(id);

        // 查询订单菜品/套餐明细
        LambdaQueryWrapper<OrderDetail> wq = new LambdaQueryWrapper<>();
        wq.eq(OrderDetail::getOrderId, id);
        List<OrderDetail> orderDetailList = orderDetailService.list(wq);

        // 封装数据返回
        OrderVO orderVO = new OrderVO();
        BeanUtils.copyProperties(order, orderVO);
        orderVO.setOrderDetailList(orderDetailList);
        return orderVO;
    }

    /**
     * 取消订单
     *
     * @param id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancelOrder(Integer id) {
        log.info("取消订单Id为{}", id);
        if (id == null || id <= 0) {
            throw new OrderBusinessException("取消订单失败！");
        }

        // 1.查询订单是否存在
        Orders order = this.getById(id);
        if (ObjectUtil.isEmpty(order)) {
            throw new OrderBusinessException("未查询到订单");
        }

        // 2.判断订单状态 1待付款 2待接单 3已接单4派送中 5已完成 6已取消 7退款
        Integer orderStatus = order.getStatus();
        // 商家已接单状态下，用户取消订单需电话沟通商家；
        if (orderStatus.equals(Orders.CONFIRMED)) {
            throw new OrderBusinessException("商家已接单暂时不能取消！请联系商家处理！");
        }
        // 商家派送中状态下，用户取消订单需电话沟通商家；
        if (orderStatus.equals(Orders.DELIVERY_IN_PROGRESS)) {
            throw new OrderBusinessException("此单正在派送中不能取消！请联系商家处理！");
        }
        // 商家接单状态下，用户可进行直接取消操作 || 待支付状态下，用户可进行直接取消操作
        if (orderStatus.equals(Orders.TO_BE_CONFIRMED) || orderStatus.equals(Orders.PAID)) {
            log.info("订单状态符合取消规则，处理取消订单");
            order.setStatus(Orders.CANCELLED);
            LambdaUpdateWrapper<Orders> queryWrapper = new LambdaUpdateWrapper<>();
            queryWrapper.eq(Orders::getId, id);
            queryWrapper.set(Orders::getStatus, Orders.CANCELLED);
            // 3.取消订单修改定订单状态
            this.update(queryWrapper);
        }

        // TODO 已付款状态订单取消，下方有一条退款成功提示；

    }

    /**
     * 再来一单
     *
     * @param id
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void repetitionOrder(Integer id) {

        // 1.健壮性判断
        if (id == null || id <= 0) {
            throw new OrderBusinessException("再来一单失败！");
        }

        // 2.根据订单id查询订单详情
        LambdaQueryWrapper<OrderDetail> wq = new LambdaQueryWrapper<>();
        wq.eq(OrderDetail::getOrderId, id);
        List<OrderDetail> orderDetailList = orderDetailService.list(wq);

        if (CollUtil.isEmpty(orderDetailList)) {
            throw new OrderBusinessException("查询原始订单详情失败！");
        }

        // 3.将订单详情转为购物车对象e
        Long userId = BaseContext.getCurrentId();
        List<ShoppingCart> shoppingCartList = orderDetailList.stream().map(orderDetail -> {
            // 4.将原订单详情里面的菜品信息重新复制到购物车对象中
            ShoppingCart shoppingCart = new ShoppingCart();
            BeanUtils.copyProperties(orderDetail, shoppingCart);
            shoppingCart.setUserId(userId);
            shoppingCart.setCreateTime(LocalDateTime.now());
            return shoppingCart;
        }).collect(Collectors.toList());

        // 5.插入购物车中
        int count = shoppingCartMapper.insertBatch(shoppingCartList);
        if (count != shoppingCartList.size()) {
            throw new OrderBusinessException("再来一单失败！");
        }
    }

    /**
     * 客户端-查询订单接口
     *
     * @param dto
     * @return
     */
    @Override
    public PageResult conditionSearch(OrdersPageQueryDTO dto) {
        // 健壮性判断
        if (ObjectUtil.isEmpty(dto)) {
            throw new OrderBusinessException("查询参数为空！");
        }
        // 1.构建分页
        Page<Orders> ordersPage = new Page<>(dto.getPage(), dto.getPageSize());

        // 2.条件查询
        this.lambdaQuery().like(StringUtils.hasLength(dto.getNumber()), Orders::getNumber, dto.getNumber()).like(StringUtils.hasLength(dto.getPhone()), Orders::getPhone, dto.getPhone()).between(dto.getBeginTime() != null && dto.getEndTime() != null, Orders::getOrderTime, dto.getBeginTime(), dto.getEndTime()).orderByDesc(Orders::getOrderTime).page(ordersPage);

        // 3. 订单状态处理
        List<Orders> records = ordersPage.getRecords();

        // 3.1 查询所有订单详情
        List<OrderDetail> allDetails = orderDetailService.list();

        // 3.2 按照 orderId 分组。键是订单ID，值是一个字符串列表，每个字符串代表该订单下的一个菜品及其数量。
        Map<Long, List<String>> detailMap = allDetails.stream().collect(Collectors.groupingBy(
                // 设置-k
                OrderDetail::getOrderId,
                // 设置-V 通过 Collectors.mapping 转换为一个新的字符串形式，该字符串由菜品名称和数量组成（例如："宫保鸡丁 * 2"）。收集到一个列表中。
                Collectors.mapping(detail -> detail.getName() + " * " + detail.getNumber(), Collectors.toList())));

        // 3.3 遍历订单记录，设置菜品名称字符串
        records.forEach(order -> {
            Long id = order.getId();
            // 根据其ID从之前构建的 detailMap 中获取对应的菜品列表。如果找不到对应条目，则返回一个空列表。
            List<String> dishNames = detailMap.getOrDefault(id, Collections.emptyList());
            // 将获取到的菜品列表转换成一个以“份”和逗号分隔的字符串。如果没有找到任何菜品，则设置默认消息“弄错菜了”。
            String dishesStr = dishNames.isEmpty() ? "弄错菜了" : String.join("份, ", dishNames);
            // 设置值
            order.setOrderDishes(dishesStr);
        });

        // 3.2处理超时订单
        List<Orders> newOrdersList = OrderStatusHandle(records);

        // 4.返回数据
        return new PageResult(ordersPage.getTotal(), newOrdersList);
    }

    /**
     * 客户端-订单状态统计
     *
     * @return
     */
    @Override
    public Map<String, Object> ordersCount() {
        // 1待付款 2待接单 3.已接单 4派送中 5已完成 6已取消 7退款
        // 1. 查询所有未取消订单
        List<Orders> ordersList = this.lambdaQuery().ne(Orders::getStatus, Orders.CANCELLED)         // 状态 != 已取消
                .ne(Orders::getStatus, Orders.CANCELLED)        // 状态 != 退款
                .ne(Orders::getStatus, Orders.REFUND)        // 状态 != 退款
                .list();

        /*超时订单处理*/
        List<Orders> newOrdersList = OrderStatusHandle(ordersList);

        // 2. 在内存中按状态分类统计
        long confirmed = newOrdersList.stream().filter(o -> o.getStatus() == Orders.CONFIRMED).count();

        long deliveryInProgress = newOrdersList.stream().filter(o -> o.getStatus() == Orders.DELIVERY_IN_PROGRESS).count();

        long toBeConfirmed = newOrdersList.stream().filter(o -> o.getStatus() == Orders.TO_BE_CONFIRMED).count();

        // 3. 返回结果
        Map<String, Object> result = new HashMap<>();
        result.put("confirmed", confirmed);
        result.put("deliveryInProgress", deliveryInProgress);
        result.put("toBeConfirmed", toBeConfirmed);

        return result;
    }

    /**
     * 接单
     *
     * @param id
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void confirm(Long id) {
        if (id == null || id <= 0) {
            throw new OrderBusinessException("接单失败，参数为空！");
        }
        // 查看订单状态,必须是待接单状态才能接单。1待付款 2待接单 3已接单 4派送中 5已完成 6已取消 7退款
        // select * from order o where o.id= 1 and o.status = 2
        Orders one = this.lambdaQuery().eq(Orders::getId, id).eq(Orders::getStatus, Orders.TO_BE_CONFIRMED).one();

        // 订单超时处理判断
        LocalDateTime orderTime = one.getOrderTime();
        // 判断订单时间是否早于 ’ 当前时间 - 15分钟
        LocalDateTime sysNow = LocalDateTime.now();
        if (orderTime != null && orderTime.isBefore(sysNow.minusMinutes(15))) {
            // 超过15分钟，更新订单状态为已取消
            one.setStatus(Orders.CANCELLED);
            this.updateById(one);
        }

        // 处理订单状态为接单
        if (!ObjectUtil.isEmpty(one) && one.getStatus().equals(Orders.TO_BE_CONFIRMED)) {
            //处理接单
            one.setStatus(Orders.CONFIRMED);
            this.updateById(one);
        } else {
            throw new OrderBusinessException("接单失败！请刷新页面");
        }
    }

    /**
     * 商家取消订单
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void cancel(Orders orders) {
        // 1.健壮性判断 1待付款 2待接单 3已接单 4派送中 5已完成 6已取消 7退款
        if (orders.getId() == null || orders.getCancelReason() == null) {
            throw new OrderBusinessException("参数为空不能取消订单！");
        }
        // 2.取消订单状态
        Orders one = this.getById(orders.getId());
        if (ObjectUtil.isNotEmpty(one)) {
            one.setStatus(Orders.CANCELLED);
            one.setCancelReason(orders.getCancelReason());
            this.updateById(one);
        } else {
            throw new OrderBusinessException("取消失败！");
        }

    }

    /**
     * 商家派单
     *
     * @param id
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delivery(Integer id) {
        if (id == null || id <= 0) {
            throw new OrderBusinessException("订单为空派送失败！");
        }
        // 查询出对应的订单信息状态为 3已接单的
        Orders orders = this.lambdaQuery().eq(Orders::getId, id).eq(Orders::getStatus, Orders.CONFIRMED).one();

        if (ObjectUtil.isEmpty(orders)) {
            throw new OrderBusinessException("暂无订单信息，派送失败！");
        }
        // 1待付款 2待接单 3已接单 4派送中 5已完成 6已取消 7退款
        orders.setStatus(Orders.DELIVERY_IN_PROGRESS);
        this.updateById(orders);
    }

    /**
     * 完成订单
     *
     * @param id
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void complete(Integer id) {
        if (id == null || id <= 0) {
            throw new OrderBusinessException("暂无完成订单id！");
        }
        // 1待付款 2待接单 3已接单 4派送中 5已完成 6已取消 7退款
        Orders one = this.lambdaQuery().eq(Orders::getId, id).eq(Orders::getStatus, Orders.DELIVERY_IN_PROGRESS).one();
        // 查看是否符合状态
        if (ObjectUtil.isEmpty(one)) {
            throw new OrderBusinessException("暂无次订单信息，请刷新尝试！");
        }
        one.setStatus(Orders.COMPLETED);
        this.updateById(one);
    }

    /**
     * 催单
     *
     * @param id
     */
    @Override
    public void reminder(Integer id) {
        if (id == null || id <= 0) {
            throw new OrderBusinessException("订单id为空，催单失败！");
        }
        Orders orders = orderMapper.selectById(id);
        HashMap map = new HashMap();
        map.put("type", 2);
        map.put("orderId", orders.getId());
        map.put("context", "订单号：" + orders.getNumber());
        String jsonString = JSON.toJSONString(map);
        webSocketServer.sendToAllClient(jsonString);
        log.info("催单！");
    }
}
